package h2.server;

import org.h2.tools.Server;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;

/**
 * 优化后的H2服务器实现，包含安全加固和性能优化
 */
public class OptimizedH2Server {
    private Server tcpServer;
    private final H2ServerConfig config;

    public OptimizedH2Server() {
        this.config = new H2ServerConfig();
    }

    public OptimizedH2Server(H2ServerConfig config) {
        this.config = config;
    }

    /**
     * 启动H2服务器
     */
    public void start() throws SQLException {
        // 验证必要配置
        validateConfig();

        // 构建服务器启动参数
        String[] serverArgs = buildServerArguments();

        System.out.println("启动H2服务器参数: " + Arrays.toString(serverArgs));

        // 启动TCP服务器
        tcpServer = Server.createTcpServer(serverArgs).start();
        System.out.println("H2服务器启动成功: " + tcpServer.getStatus());

        // 初始化数据库和用户
        initializeDatabase();

        // 打印连接信息
        printConnectionInfo();
    }

    /**
     * 验证必要的配置参数
     */
    private void validateConfig() {
        if (config.getAdminPassword() == null || config.getAdminPassword().trim().isEmpty()) {
            throw new IllegalArgumentException("管理员密码不能为空，请在配置文件中设置h2.admin.password或环境变量H2_ADMIN_PASSWORD");
        }

        if (config.isSslEnabled() && (config.getKeystorePassword() == null || config.getKeystorePassword().isEmpty())) {
            throw new IllegalArgumentException("SSL已启用，但密钥库密码未设置，请设置h2.ssl.keystore.password或环境变量H2_KEYSTORE_PASSWORD");
        }
    }

    /**
     * 构建服务器启动参数
     */
    private String[] buildServerArguments() {
        // 基础参数
        String[] baseArgs = {
                "-tcpPort", String.valueOf(config.getTcpPort()),
                "-ifNotExists",                   // 不存在则创建数据库
                "-tcpMaxConnections", String.valueOf(config.getMaxConnections()),
                "-tcpConnectionTimeout", String.valueOf(config.getConnectionTimeout())
        };

        // 动态参数列表
        java.util.List<String> argsList = new java.util.ArrayList<>(Arrays.asList(baseArgs));

        // 远程访问配置
        if (config.isAllowRemote()) {
            argsList.add("-tcpAllowOthers");
        }

        // SSL配置
        if (config.isSslEnabled()) {
            argsList.add("-ssl");
            argsList.add("-keystore");
            argsList.add(config.getKeystorePath());
            argsList.add("-keystorePassword");
            argsList.add(config.getKeystorePassword());
        }

        return argsList.toArray(new String[0]);
    }

    /**
     * 初始化数据库和用户权限
     */
    private void initializeDatabase() throws SQLException {
        // 使用默认用户sa连接（首次创建数据库时需要）
        try (Connection conn = DriverManager.getConnection(
                config.getJdbcUrl().replace(";SSL=true", ""),  // 首次创建不使用SSL
                "sa", "")) {

            Statement stmt = conn.createStatement();

            // 启用数据库加密
            stmt.executeUpdate("ALTER DATABASE ENABLE ENCRYPTION IF NOT ENABLED");

            // 创建管理员用户并授权
            stmt.executeUpdate(String.format(
                    "CREATE USER IF NOT EXISTS %s PASSWORD '%s'",
                    config.getAdminUser(), config.getAdminPassword()
            ));
            stmt.executeUpdate(String.format(
                    "GRANT ALL ON SCHEMA PUBLIC TO %s",
                    config.getAdminUser()
            ));

            // 创建只读用户并授权
            stmt.executeUpdate(String.format(
                    "CREATE USER IF NOT EXISTS %s PASSWORD '%s'",
                    config.getReaderUser(), config.getReaderPassword()
            ));
            stmt.executeUpdate(String.format(
                    "GRANT SELECT ON SCHEMA PUBLIC TO %s",
                    config.getReaderUser()
            ));

            // 设置密码策略
            stmt.executeUpdate("SET PROPERTY 'PASSWORD_HASH' = 'SHA256'");
            stmt.executeUpdate("SET PROPERTY 'PASSWORD_MIN_LENGTH' = '8'");

            // 优化数据库参数
            stmt.executeUpdate("SET PROPERTY 'MAX_MEMORY_ROWS' = '10000'");
            stmt.executeUpdate("SET PROPERTY 'CACHE_SIZE' = '65536'");

            System.out.println("数据库初始化完成，用户和权限配置已生效");
        }
    }

    /**
     * 打印连接信息
     */
    private void printConnectionInfo() {
        System.out.println("\n===== H2服务器连接信息 =====");
        System.out.println("JDBC URL: " + config.getJdbcUrl());
        System.out.println("管理员用户: " + config.getAdminUser());
        System.out.println("只读用户: " + config.getReaderUser());
        System.out.println("SSL启用: " + (config.isSslEnabled() ? "是" : "否"));
        System.out.println("最大连接数: " + config.getMaxConnections());
        System.out.println("===========================\n");
    }

    /**
     * 停止H2服务器
     */
    public void stop() {
        if (tcpServer != null) {
            tcpServer.stop();
            System.out.println("H2服务器已停止");
        }
    }

    /**
     * 主方法：启动服务器
     */
    public static void main(String[] args) {
        // 注册关闭钩子，确保程序退出时正确停止服务器
        OptimizedH2Server server = new OptimizedH2Server();
        Runtime.getRuntime().addShutdownHook(new Thread(server::stop));

        try {
            server.start();
            System.out.println("H2服务器运行中，按Ctrl+C停止...");

            // 保持服务器运行
            synchronized (server) {
                server.wait();
            }
        } catch (Exception e) {
            System.err.println("H2服务器启动失败: " + e.getMessage());
            e.printStackTrace();
            System.exit(1);
        }
    }
}
    